package com.study.juc.lk;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @program: juc-study
 * @author: jzhou
 * @date: 2022-08-16 16:03
 * @version: 1.0
 * @description: 自旋锁，需要使用“原子引用”中的compareAndSet方法，而不是Java内部提供的锁方法
 * 题目：实现一个自旋锁
 * 自旋锁好处：循环比较获取没有类似wait的阻塞。
 *
 * 通过CAS操作完成自旋锁，A线程先进来调用myLock方法自己持有锁5秒钟，B随后进来后发现
 * 当前有线程持有锁，不是null，所以只能通过自旋等待，直到A释放锁后B随后抢到。
 **/
public class SpinLockDemo {

	AtomicReference<Thread> atomicReference = new AtomicReference<>();

	/**
	 * 借鉴CAS思想，使用循环等待的方式实现类似锁的功能
	 * 需要使用“原子引用”中的compareAndSet方法
	 */
	public void lock(){
		Thread thread = Thread.currentThread();
		System.out.println(thread.getName() + "\t come in");
		while (!atomicReference.compareAndSet(null, thread)) {

		}
	}

	public void unlock(){
		Thread thread = Thread.currentThread();
		System.out.println(thread.getName() + "\t task over");
		atomicReference.compareAndSet(thread,null);
	}

	public static void main(String[] args) {
		SpinLockDemo spinLockDemo = new SpinLockDemo();

		new Thread(() -> {
			spinLockDemo.lock();
			// 执行自己逻辑，结束后释放锁
			try {
				TimeUnit.SECONDS.sleep(5);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			spinLockDemo.unlock();
		},"A").start();
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		new Thread(() -> {
			spinLockDemo.lock();
			// 执行自己逻辑，结束后释放锁
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i);
			}
			spinLockDemo.unlock();
		},"B").start();
	}
}
